package compress

import (
	"archive/tar"
	"changeme/backend/utils"
	"fmt"
	"io"
	"io/fs"
	"os"
	"path/filepath"
)

func Tar(path string, createPath string) (err error) {
	if _, exist := utils.Exist(path); !exist {
		return fs.ErrNotExist
	}

	tarFile, err := os.OpenFile(createPath, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0755)
	defer func() {
		_ = tarFile.Close()
	}()
	if err != nil {
		return err
	}

	tarWriter := tar.NewWriter(tarFile)
	defer func() {
		_ = tarWriter.Close()
	}()
	err = TarCompress("", path, tarWriter)
	return
}

func TarCompress(prefix string, path string, w *tar.Writer) (err error) {
	info, exist := utils.Exist(path)
	if !exist {
		return fs.ErrNotExist
	}

	file, err := os.Open(path)
	defer func() {
		_ = file.Close()
	}()
	if err != nil {
		return err
	}

	if info.IsDir() {
		prefix = filepath.Join(prefix, info.Name())
		fileInfos, err := file.Readdir(-1)
		if err != nil {
			return err
		}

		for _, fileInfo := range fileInfos {
			err = TarCompress(prefix, filepath.Join(file.Name(), fileInfo.Name()), w)
			if err != nil {
				return err
			}
		}
	} else {
		header, err := tar.FileInfoHeader(info, "")
		if err != nil {
			return err
		}
		header.Name = filepath.Join(prefix, header.Name)

		err = w.WriteHeader(header)
		if err != nil {
			return err
		}

		_, err = io.Copy(w, file)
		if err != nil {
			return err
		}
	}
	return
}

func UnTar(absFilePath string, extractPath string) (err error) {
	if !utils.ExistFile(absFilePath) {
		return fs.ErrNotExist
	}

	tarFile, err := os.Open(absFilePath)
	if err != nil {
		return err
	}

	path, err := filepath.Abs(extractPath)
	if err != nil {
		return err
	}

	fmt.Printf("解压 %s \n\t=> %s\n", absFilePath, path)
	tarReader := tar.NewReader(tarFile)
	for {
		file, err := tarReader.Next()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				return err
			}
		}

		if utils.EndWith(file.Name, "/") {
			err = os.MkdirAll(filepath.Join(path, file.Name), 0755)
			if err != nil {
				return err
			}
		} else {
			target, err := os.Create(filepath.Join(path, file.Name))
			if err != nil {
				return err
			}
			_, err = io.Copy(target, tarReader)
			if err != nil {
				return err
			}
			_ = target.Close()
		}
	}

	return
}
